<?php
declare (strict_types=1);

namespace app\promotion\logic;

use app\common\exception\LogicException;
use ArrayObject;
use Exception;
use app\common\model\payment\{PaymentOrderItem as POI};
use app\course\logic\base\{Course};
use app\course\logic\classes\Classes;
use app\promotion\model\PromotionTuan as PromotionTuanModel;
use app\user\logic\user\{Credit};
use think\facade\{Db, Request};
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

/**
 * 团购逻辑层
 */
class PromotionTuan extends PromotionTuanModel
{

    public function getUserJoinTuanData($promotion_id, $user_id = 0)
    {
        $mid  = $user_id ?: request()->mid;
        $sql  = app(PromotionTuanData::class)->alias('tuan_data')
            ->join('promotion_tuan tuan', "`tuan`.`id`=`tuan_data`.`tuan_id` AND `tuan`.`promotion_id`=$promotion_id AND `tuan_data`.`user_id`=$mid")
            ->field('tuan_data.*,tuan.user_id as sponsor,tuan.status as tuan_status')
            ->buildSql();
        $data = Db::query($sql);

        return current($data);
    }

    /**
     * 获取用户入团的基础信息
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-14
     *
     * @param int $promotion_id [description]
     * @return PromotionTuan|array|Model [type]                    [description]
     */
    public function getUserTuanBase(int $promotion_id)
    {
        $data = $this->getUserJoinTuanData($promotion_id);
        //
        if ($data) {
            $tuan_id = $data['tuan_id'];
            // 检查订单
            $order = app(POI::class)->whereUserId(request()->mid)->wherePromotionId($promotion_id)->with(['order_status'])->order('order_no DESC')->findOrEmpty();
            if ($data['sponsor'] == $data['user_id']) {
                return (!$order->isEmpty() && in_array($order->status, [10, 80])) ? $this->findOrEmpty($tuan_id) : $this->findOrEmpty(0)->append();
            }
            return (!$order->isEmpty() && $order->status == 80) ? $this->findOrEmpty($tuan_id) : $this->findOrEmpty(0)->append();
        }
        return $this->findOrEmpty(0)->append();
    }

    /**
     * 获取用户入团的基础信息
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-14
     *
     * @param int $promotion_id [description]
     * @return PromotionTuan|array|Model [type]                    [description]
     */
    public function getUserPositiveTuan(int $promotion_id)
    {
        $data = $this->getUserJoinTuanData($promotion_id);
        //
        return ($data && in_array($data['tuan_status'], [0, 1, 2])) ? $this->findOrEmpty($data['tuan_id']) : $this->findOrEmpty(0)->append();
    }

    /**
     * 获取用户入团数据【不区分开团或参团，均返回存在团的团员数据】
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-14
     *
     * @param int $promotion_id [description]
     * @return PromotionTuan|array|ArrayObject|Model [type]                    [description]
     */
    public function getUserTuanData(int $promotion_id)
    {
        $data = $this->getUserJoinTuanData($promotion_id);
        return $data ? $this->with(['tuan_data'])->findOrEmpty($data['tuan_id']) : new ArrayObject();
    }

    /**
     * 当前活动用户入团数据
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-15
     *
     * @param int $promotion_id
     * @return false|mixed [type]          [description]
     */
    public function promotionUserTuanData(int $promotion_id)
    {
        $mid  = request()->mid;
        $data = $this->alias('t')
            ->join('promotion_tuan_data d', "t.id=d.tuan_id AND t.promotion_id=$promotion_id AND d.user_id=$mid AND d.delete_time is null")
            ->field('t.*, d.id as tuan_data_id')
            ->buildSql();
        $data = Db::query($data);
        return current($data);
    }

    /**
     * 检查订单，有订单时不可入团，无订单可以参加其他团，或重新开团
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-05-27
     *
     * @param int $promotion_id [description]
     * @return void [type]               [description]
     */
    public function checkOrderStatus(int $promotion_id)
    {
        $order = app(POI::class)->alias('i')
            ->join('payment_order o', "i.order_no=o.order_no AND o.status <> 0")
            ->field('o.status,i.*')
            ->wherePromotionId($promotion_id)
            ->where('i.user_id', request()->mid)
            ->findOrEmpty();

        if (!$order->isEmpty()) {
            if ($order->status == 10) throw new LogicException("您已参加团购活动，请确认支付");
            if ($order->status == 80) throw new LogicException("您已参加团购活动，请勿重复操作");
        }
    }

    /**
     * 发起拼团
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-14
     *
     * @param array $param [description]
     * @return Course|array|Model [type]        [description]
     * @throws Exception
     */
    public function createUserTuan(array $param)
    {
        // 数据验证
        $this->getValidate()->scene('create')->failException()->check($param);
        // 参数
        $promotion_id = intval($param['promotion_id']);
        $mid          = request()->mid;
        // 活动过期
        $promotion = app(Promotion::class)->getPositivePromotionInfo($promotion_id);
        if ($promotion->isEmpty()) throw new LogicException("团已失效，不能入团");
        // 检查订单，有订单时不可入团，无订单可以参加其他团，或重新开团
        $this->checkOrderStatus($promotion_id);

        Db::startTrans();
        // 存在入团信息
        $exist_tuan = $this->promotionUserTuanData($promotion_id);

        if ($exist_tuan && $exist_tuan['user_id'] == $mid) {
            // 存在开团信息
            $tuan = $this->findOrEmpty($exist_tuan['id']);
            // 删除原开团订单
            if (!$tuan->delete()) throw new LogicException("开团失败，请重试");
        }

        // 存在入团数据判断
        if ($exist_tuan && $exist_tuan['tuan_data_id']) {
            // 删除开团时入团数据
            $exist_tuan_data = app(PromotionTuanData::class)->findOrEmpty($exist_tuan['tuan_data_id']);
            if (!$exist_tuan_data->delete()) throw new LogicException("入团失败，请重试");
        }

        try {
            // 发起
            $create = [
                'promotion_id' => $promotion_id,
                'user_id'      => $mid,
                'total_num'    => $promotion->num,
                'expiry_time'  => min($promotion->expiry * 3600 + Request::time(), $promotion->end_time),
            ];
            // 创建
            $tuan = $this::create($create);
            if ($tuan->isEmpty()) throw new LogicException("开团失败，请重试");
            //
            $tuan_data = PromotionTuanData::create(['tuan_id' => $tuan->id, 'user_id' => $mid]);
            if ($tuan_data->isEmpty()) throw new LogicException("开团失败，请重试.");

            Db::commit();
        } catch (LogicException $e) {
            Db::rollback();
            throw new LogicException($e->getMessage());
        } catch (Exception $e) {
            Db::rollback();
            throw $e;
        }

        return $this->orderFetch($promotion->product_id, $promotion->toArray());
    }

    /**
     * 加入团购
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-15
     *
     * @param array $param
     * @return Course|array|Model [type] [description]
     * @throws Exception
     */
    public function joinUserTuan(array $param)
    {
        // 数据验证
        $this->getValidate()->scene('join')->failException()->check($param);
        // 参数
        $tuan_id = intval($param['tuan_id']);
        $mid     = request()->mid;
        // 团购信息
        $tuan = $this->findOrFail($tuan_id);
        // 团已失效，不能入团
        if ($tuan->expiry_time < Request::time()) throw new LogicException("团已失效，不能入团");
        // 团已满，不能入团
        if ($tuan->join_num >= $tuan->total_num) throw new LogicException("团已满，不能入团");
        // 不能加入自己开的团
        if ($tuan->user_id == $mid) throw new LogicException("不能加入自己开的团");
        // 活动ID
        $promotion_id = intval($tuan->promotion_id);
        // 检查订单，有订单时不可入团，无订单可以参加其他团，或重新开团
        $this->checkOrderStatus($promotion_id);
        //
        Db::startTrans();
        try {
            // 存在入团数据
            $exist_tuan = $this->promotionUserTuanData($promotion_id);

            if (!$exist_tuan) {
                // 创建入团数据
                $tuan_data = PromotionTuanData::create(['tuan_id' => $tuan_id, 'user_id' => $mid]);
                if ($tuan_data->isEmpty()) throw new LogicException("入团失败，请重试.");
            } else {
                // 存在未成功开团信息
                $user_tuan = $this->whereStatus(0)->findOrEmpty($exist_tuan['id']);
                // 删除原开团订单
                if (!$user_tuan->isEmpty() && !$user_tuan->delete()) throw new LogicException("入团失败，请重试..");
                // 修改开团时入团数据
                $tuan_data              = app(PromotionTuanData::class)->findOrEmpty($exist_tuan['tuan_data_id']);
                $tuan_data->tuan_id     = $tuan_id;
                $tuan_data->create_time = Request::time();
                if (!$tuan_data->save()) throw new LogicException("入团失败，请重试....");
            }

            Db::commit();
        } catch (LogicException $e) {
            Db::rollback();
            throw new LogicException($e->getMessage());
        } catch (Exception $e) {
            Db::rollback();
            throw $e;
        }
        //
        $promotion = app(Promotion::class)->getPositivePromotionInfo($promotion_id);

        return $this->orderFetch($promotion->product_id, $promotion->toArray());
    }

    /**
     * 订单信息
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-30
     *
     * @param int   $course_id [description]
     * @param array $promotion
     * @return Course|array|Model [type]            [description]
     */
    public function orderFetch(int $course_id, array $promotion)
    {
        $course = app(Course::class)
            ->field('id,cover,title,price,vip_price,term_time,mhm_id,course_type,credit_redeem,credit_redeem_percent')
            ->with(['cover_url'])
            ->withCount(['section_count' => 'section_count'])
            ->where('id', $course_id)
            ->findOrFail()
            ->append(['course_type_text', 'user_price']);

        // 班级课处理
        if ($course->course_type == 4) {
            $course->section_count = app(Classes::class)->getClassesSectionCount($course->id);
        }

        $course->positive_promotion = $promotion;
        $course->credit_arr         = [];
        if ($course->credit_redeem) {
            $course->credit_arr = app(Credit::class)->getUserCreditRedeemArr(intval($promotion['price'] * $course->credit_redeem_percent / 100));
        }
        return $course;
    }

    /**
     * 获取团详情页数据
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-15
     *
     * @param array $param 请求参数
     * @return PromotionTuan|array|Model [type]        [description]
     */
    public function getUserTuanDetail(array $param)
    {
        // 数据验证
        $this->getValidate()->scene('detail')->failException()->check($param);
        // 参数
        $tuan_id = intval($param['tuan_id']);
        // 课程信息【类型、名称、价格、封面】、团信息、团员信息
        $data = $this
            ->withCount(['join_status' => 'join_status'])
            ->with([
                'promotion' => function ($query) {
                    $query->with(['product_info'])->bind(['price', 'product_id', 'product_title', 'product_type', 'product_type_text', 'product_price', 'product_cover', 'promotion_type' => 'type', 'promotion_type_text' => 'type_text']);
                },
                'tuan_data' => function ($query) {
                    $query->with(['user_avatar_name'])->status()->hidden(['id', 'tuan_id', 'create_time', 'status']);
                }
            ])
            ->findOrEmpty($tuan_id);
        if ($data->isEmpty()) throw new LogicException("团购活动不存在");

        $data->expiry_countdown = $data->expiry_time - time();

        return $data;
    }

    /**
     * 获取课程已开团列表
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-20
     *
     * @param array $param [description]
     * @return mixed [type]        [description]
     */
    public function getCourseTuanList(array $param)
    {
        // 数据验证
        $this->getValidate()->scene('course')->failException()->check($param);
        // 参数
        $promotion_id = intval($param['promotion_id']);

        return $this->with(['user_avatar_name'])
            ->wherePromotionId($promotion_id)
            ->where('status', 1)
            ->where('expiry_time', '>', time())
            ->whereColumn('total_num', '>', 'join_num')
            ->select();
    }

    /**
     * 获取失败的团
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-25
     *
     * @return PromotionTuan[]|array|Collection [type] [description]
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getFailedUnrefundTuan()
    {
        return $this->where('expiry_time', '<', time())->whereColumn('join_num', '<', 'total_num')->where('status', '<>', 3)->limit(100)->select();
    }

    /**
     * 删除用户拼团信息，用于取消订单
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-06-08
     */
    public function deleteUserTuan(int $promotion_id, int $user_id)
    {
        $data = $this->getUserJoinTuanData($promotion_id, $user_id);
        if ($data) {
            // 开团
            if ($data['sponsor'] == $data['user_id']) {
                $tuan = $this->findOrEmpty($data['tuan_id']);
                if (!$tuan->delete()) throw new LogicException('删除失败');
            }
            // 团data
            $tuan_data = app(PromotionTuanData::class)->findOrEmpty($data['id']);
            if (!$tuan_data->delete()) throw new LogicException('删除失败');
        }
    }

}
